diff --git a/Classes/Console/Command/Upgrade/EnsureExtensionCompatibilityTrait.php b/Classes/Console/Command/Upgrade/EnsureExtensionCompatibilityTrait.php new file mode 100644 index 000000000..42b839670 --- /dev/null +++ b/Classes/Console/Command/Upgrade/EnsureExtensionCompatibilityTrait.php @@ -0,0 +1,34 @@ +upgradeHandling->ensureExtensionCompatibility(); + if (!empty($messages)) { + $this->output->writeln('Incompatible extensions found, aborting.'); + + foreach ($messages as $message) { + $this->output->writeln($message); + } + + return false; + } + + return true; + } +} diff --git a/Classes/Console/Command/Upgrade/UpgradeAllCommand.php b/Classes/Console/Command/Upgrade/UpgradeAllCommand.php new file mode 100644 index 000000000..352b0887b --- /dev/null +++ b/Classes/Console/Command/Upgrade/UpgradeAllCommand.php @@ -0,0 +1,94 @@ +upgradeHandling = $upgradeHandling ?? new UpgradeHandling(); + } + + protected function configure() + { + $this->setDescription('Execute all upgrade wizards that are scheduled for execution'); + $this->addOption( + self::OPT_ARGUMENTS, + 'a', + InputOption::VALUE_REQUIRED, + 'Arguments for the wizard prefixed with the identifier, e.g. compatibility7Extension[install]=0; multiple arguments separated with comma', + [] + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->output = $output; + + if (!$this->ensureExtensionCompatibility()) { + return 1; + } + + $arguments = $input->getArgument(self::ARG_ARGUMENTS); + $verbose = $output->isVerbose(); + + $output->writeln(PHP_EOL . 'Initiating TYPO3 upgrade' . PHP_EOL); + + $messages = []; + $results = $this->upgradeHandling->executeAll($arguments, $this->output, $messages); + + $output->outputLine(PHP_EOL . PHP_EOL . 'Successfully upgraded TYPO3 to version %s', [TYPO3_version]); + + if ($verbose) { + $output->writeln(''); + $output->writeln('Upgrade report:'); + (new UpgradeWizardResultRenderer())->render($results, new ConsoleOutput($output, $input)); + } + + $output->writeln(''); + foreach ($messages as $message) { + $output->writeln($message); + } + } +} diff --git a/Classes/Console/Command/Upgrade/UpgradeCheckExtensionCompatibilityCommand.php b/Classes/Console/Command/Upgrade/UpgradeCheckExtensionCompatibilityCommand.php new file mode 100644 index 000000000..69910ee34 --- /dev/null +++ b/Classes/Console/Command/Upgrade/UpgradeCheckExtensionCompatibilityCommand.php @@ -0,0 +1,75 @@ +upgradeHandling = $upgradeHandling ?? new UpgradeHandling(); + } + + protected function configure() + { + $this->setDescription('Checks for broken extensions'); + $this->setHelp( + <<<'EOH' +This command in meant to be executed as sub process as it is is subject to cause fatal errors +when extensions have broken (incompatible) code +EOH + ); + $this->addArgument( + self::ARG_EXTENSION_KEY, + InputArgument::REQUIRED, + 'Extension key for extension to check' + ); + $this->addOption( + self::OPT_CONFIG_ONLY, + 'c', + InputOption::VALUE_NONE, + '' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $extensionKey = $input->getArgument(self::ARG_EXTENSION_KEY); + $configOnly = $input->getOption(self::OPT_CONFIG_ONLY); + + $output->writeln(\json_encode($this->upgradeHandling->isCompatible($extensionKey, $configOnly))); + } +} diff --git a/Classes/Console/Command/Upgrade/UpgradeCheckExtensionConstraintsCommand.php b/Classes/Console/Command/Upgrade/UpgradeCheckExtensionConstraintsCommand.php new file mode 100644 index 000000000..7c26a161c --- /dev/null +++ b/Classes/Console/Command/Upgrade/UpgradeCheckExtensionConstraintsCommand.php @@ -0,0 +1,106 @@ +upgradeHandling = $upgradeHandling ?? new UpgradeHandling(); + } + + protected function configure() + { + $this->setDescription('Check TYPO3 version constraints of extensions'); + $this->setHelp( + <<<'EOH' +This command is especially useful **before** switching sources to a new TYPO3 version. +It checks the version constraints of all third party extensions against a given TYPO3 version. +It therefore relies on the constraints to be correct. +EOH + ); + $this->addArgument( + self::ARG_EXTENSION_KEYS, + InputArgument::OPTIONAL, + 'Extension keys to check. Separate multiple extension keys with comma', + '' + ); + $this->addOption( + self::OPT_TYPO3_VERSION, + null, + InputOption::VALUE_REQUIRED, + 'TYPO3 version to check against. Defaults to current TYPO3 version', + TYPO3_version + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $extensionKeys = explode(',', $input->getArgument(self::ARG_EXTENSION_KEYS)); + $typo3Version = $input->getOption(self::OPT_TYPO3_VERSION); + + if (empty($extensionKeys)) { + $failedPackageMessages = $this->upgradeHandling->matchAllExtensionConstraints($typo3Version); + } else { + $failedPackageMessages = []; + foreach ($extensionKeys as $extensionKey) { + try { + if (!empty($result = $this->upgradeHandling->matchExtensionConstraints($extensionKey, $typo3Version))) { + $failedPackageMessages[$extensionKey] = $result; + } + } catch (UnknownPackageException $e) { + $output->writeln(sprintf( + 'Extension "%s" is not found in the system', + $extensionKey + )); + } + } + } + foreach ($failedPackageMessages as $constraintMessage) { + $output->writeln(sprintf('%s', $constraintMessage)); + } + if (empty($failedPackageMessages)) { + $output->writeln(sprintf( + 'All third party extensions claim to be compatible with TYPO3 version %s', + $typo3Version + )); + } else { + return 1; + } + } +} diff --git a/Classes/Console/Command/Upgrade/UpgradeListCommand.php b/Classes/Console/Command/Upgrade/UpgradeListCommand.php new file mode 100644 index 000000000..7689d87b1 --- /dev/null +++ b/Classes/Console/Command/Upgrade/UpgradeListCommand.php @@ -0,0 +1,87 @@ +upgradeHandling = $upgradeHandling ?? new UpgradeHandling(); + } + + protected function configure() + { + $this->setDescription('List upgrade wizards'); + $this->addOption( + self::OPT_ALL, + 'a', + InputOption::VALUE_NONE, + 'If set, all wizards will be listed, even the once marked as ready or done' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->output = $output; + + if (!$this->ensureExtensionCompatibility()) { + return 1; + } + + $all = $input->getOption(self::OPT_ALL); + $verbose = $output->isVerbose(); + + $wizards = $this->upgradeHandling->executeInSubProcess('listWizards', []); + + $listRenderer = new UpgradeWizardListRenderer(); + $consoleOutput = new ConsoleOutput($output, $input); + + $output->writeln('Wizards scheduled for execution:'); + $listRenderer->render($wizards['scheduled'], $consoleOutput, $verbose); + + if ($all) { + $output->writeln(PHP_EOL . 'Wizards marked as done:'); + $listRenderer->render($wizards['done'], $consoleOutput, $verbose); + } + } +} diff --git a/Classes/Console/Command/Upgrade/UpgradeSubProcessCommand.php b/Classes/Console/Command/Upgrade/UpgradeSubProcessCommand.php new file mode 100644 index 000000000..be698150f --- /dev/null +++ b/Classes/Console/Command/Upgrade/UpgradeSubProcessCommand.php @@ -0,0 +1,75 @@ +upgradeHandling = $upgradeHandling ?? new UpgradeHandling(); + } + + protected function configure() + { + $this->setDescription('This is where the hard work happens in a fully bootstrapped TYPO3'); + $this->setHelp('It will be called as sub process'); + $this->addArgument( + self::ARG_UPGRADE_COMMAND, + InputArgument::REQUIRED + ); + $this->addArgument( + self::ARG_ARGUMENTS, + InputArgument::REQUIRED, + 'Serialized arguments' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $upgradeCommand = $input->getArgument(self::ARG_UPGRADE_COMMAND); + $arguments = $input->getArgument(self::ARG_ARGUMENTS); + + $arguments = unserialize($arguments, ['allowed_classes' => false]); + $result = $this->upgradeHandling->$upgradeCommand(...$arguments); + $output->writeln(serialize($result)); + } +} diff --git a/Classes/Console/Command/Upgrade/UpgradeWizardCommand.php b/Classes/Console/Command/Upgrade/UpgradeWizardCommand.php new file mode 100644 index 000000000..98ff513c5 --- /dev/null +++ b/Classes/Console/Command/Upgrade/UpgradeWizardCommand.php @@ -0,0 +1,98 @@ +upgradeHandling = $upgradeHandling ?? new UpgradeHandling(); + } + + protected function configure() + { + $this->setDescription('Execute a single upgrade wizard'); + $this->addArgument( + self::ARG_IDENTIFIER, + InputArgument::REQUIRED, + 'Identifier of the wizard that should be executed' + ); + $this->addOption( + self::OPT_ARGUMENTS, + 'a', + InputOption::VALUE_REQUIRED, + 'Arguments for the wizard prefixed with the identifier, e.g. compatibility7Extension[install]=0', + [] + ); + $this->addOption( + self::OPT_FORCE, + 'f', + InputOption::VALUE_NONE, + 'Force execution, even if the wizard has been marked as done' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->output = $output; + + if (!$this->ensureExtensionCompatibility()) { + return 1; + } + + $identifier = $input->getArgument(self::ARG_IDENTIFIER); + $arguments = $input->getOption(self::OPT_ARGUMENTS); + $force = $input->getOption(self::OPT_FORCE); + + $result = $this->upgradeHandling->executeInSubProcess( + 'executeWizard', + [$identifier, $arguments, $force] + ); + + (new UpgradeWizardResultRenderer())->render([$identifier => $result], new ConsoleOutput($output, $input)); + } +} diff --git a/Classes/Console/Command/UpgradeCommandController.php b/Classes/Console/Command/UpgradeCommandController.php deleted file mode 100644 index 8a7fb0efb..000000000 --- a/Classes/Console/Command/UpgradeCommandController.php +++ /dev/null @@ -1,190 +0,0 @@ -upgradeHandling = $upgradeHandling ?: new UpgradeHandling(); - } - - /** - * Check TYPO3 version constraints of extensions - * - * This command is especially useful **before** switching sources to a new TYPO3 version. - * It checks the version constraints of all third party extensions against a given TYPO3 version. - * It therefore relies on the constraints to be correct. - * - * @param array $extensionKeys Extension keys to check. Separate multiple extension keys with comma. - * @param string $typo3Version TYPO3 version to check against. Defaults to current TYPO3 version. - * @Definition\Argument(name="extensionKeys") - */ - public function checkExtensionConstraintsCommand(array $extensionKeys = [], $typo3Version = TYPO3_version) - { - if (empty($extensionKeys)) { - $failedPackageMessages = $this->upgradeHandling->matchAllExtensionConstraints($typo3Version); - } else { - $failedPackageMessages = []; - foreach ($extensionKeys as $extensionKey) { - try { - if (!empty($result = $this->upgradeHandling->matchExtensionConstraints($extensionKey, $typo3Version))) { - $failedPackageMessages[$extensionKey] = $result; - } - } catch (UnknownPackageException $e) { - $this->outputLine('Extension "%s" is not found in the system', [$extensionKey]); - } - } - } - foreach ($failedPackageMessages as $constraintMessage) { - $this->outputLine('%s', [$constraintMessage]); - } - if (empty($failedPackageMessages)) { - $this->outputLine('All third party extensions claim to be compatible with TYPO3 version %s', [$typo3Version]); - } else { - $this->quit(1); - } - } - - /** - * List upgrade wizards - * - * @param bool $all If set, all wizards will be listed, even the once marked as ready or done - */ - public function listCommand($all = false) - { - $this->ensureExtensionCompatibility(); - $verbose = $this->output->getSymfonyConsoleOutput()->isVerbose(); - $messages = []; - $wizards = $this->upgradeHandling->executeInSubProcess('listWizards', [], $messages); - - $listRenderer = new UpgradeWizardListRenderer(); - $this->outputLine('Wizards scheduled for execution:'); - $listRenderer->render($wizards['scheduled'], $this->output, $verbose); - - if ($all) { - $this->outputLine(PHP_EOL . 'Wizards marked as done:'); - $listRenderer->render($wizards['done'], $this->output, $verbose); - } - $this->outputLine(); - foreach ($messages as $message) { - $this->outputLine($message); - } - } - - /** - * Execute a single upgrade wizard - * - * @param string $identifier Identifier of the wizard that should be executed - * @param array $arguments Arguments for the wizard prefixed with the identifier, e.g. compatibility7Extension[install]=0 - * @param bool $force Force execution, even if the wizard has been marked as done - */ - public function wizardCommand($identifier, array $arguments = [], $force = false) - { - $this->ensureExtensionCompatibility(); - $messages = []; - $result = $this->upgradeHandling->executeInSubProcess('executeWizard', [$identifier, $arguments, $force], $messages); - (new UpgradeWizardResultRenderer())->render([$identifier => $result], $this->output); - $this->outputLine(); - foreach ($messages as $message) { - $this->outputLine($message); - } - } - - /** - * Execute all upgrade wizards that are scheduled for execution - * - * @param array $arguments Arguments for the wizard prefixed with the identifier, e.g. compatibility7Extension[install]=0; multiple arguments separated with comma - */ - public function allCommand(array $arguments = []) - { - $this->ensureExtensionCompatibility(); - $verbose = $this->output->getSymfonyConsoleOutput()->isVerbose(); - $this->outputLine(PHP_EOL . 'Initiating TYPO3 upgrade' . PHP_EOL); - - $messages = []; - $results = $this->upgradeHandling->executeAll($arguments, $this->output, $messages); - - $this->outputLine(PHP_EOL . PHP_EOL . 'Successfully upgraded TYPO3 to version %s', [TYPO3_version]); - - if ($verbose) { - $this->outputLine(); - $this->outputLine('Upgrade report:'); - (new UpgradeWizardResultRenderer())->render($results, $this->output); - } - $this->outputLine(); - foreach ($messages as $message) { - $this->outputLine($message); - } - } - - private function ensureExtensionCompatibility() - { - $messages = $this->upgradeHandling->ensureExtensionCompatibility(); - if (!empty($messages)) { - $this->outputLine('Incompatible extensions found, aborting.'); - foreach ($messages as $message) { - $this->outputLine($message); - } - $this->quit(1); - } - } - - /** - * This is where the hard work happens in a fully bootstrapped TYPO3 - * It will be called as sub process - * - * @param string $upgradeCommand - * @param string $arguments Serialized arguments - * @internal - */ - public function subProcessCommand($upgradeCommand, $arguments) - { - $arguments = unserialize($arguments, ['allowed_classes' => false]); - $result = $this->upgradeHandling->$upgradeCommand(...$arguments); - $this->output(serialize($result)); - } - - /** - * Checks for broken extensions - * - * This command in meant to be executed as sub process as it is is subject to cause fatal errors - * when extensions have broken (incompatible) code - * - * @param string $extensionKey Extension key for extension to check - * @param bool $configOnly - * @internal - */ - public function checkExtensionCompatibilityCommand($extensionKey, $configOnly = false) - { - $this->output(\json_encode($this->upgradeHandling->isCompatible($extensionKey, $configOnly))); - } -} diff --git a/Classes/Console/Install/Upgrade/UpgradeHandling.php b/Classes/Console/Install/Upgrade/UpgradeHandling.php index 828b8287c..a46a44df4 100644 --- a/Classes/Console/Install/Upgrade/UpgradeHandling.php +++ b/Classes/Console/Install/Upgrade/UpgradeHandling.php @@ -123,7 +123,7 @@ public function executeAll(array $arguments, ConsoleOutput $consoleOutput, array $consoleOutput->progressStart(rand(6, 9)); $consoleOutput->progressAdvance(); - $wizards = $this->executeInSubProcess('listWizards', [], $messages); + $wizards = $this->executeInSubProcess('listWizards', []); $consoleOutput->progressStart(count($wizards['scheduled']) + 2); diff --git a/Configuration/Commands.php b/Configuration/Commands.php index 6fe333678..670272551 100644 --- a/Configuration/Commands.php +++ b/Configuration/Commands.php @@ -278,10 +278,8 @@ ], 'upgrade:all' => [ 'vendor' => 'typo3_console', - 'class' => \Helhum\Typo3Console\Mvc\Cli\Symfony\Command\DummyCommand::class, + 'class' => \Helhum\Typo3Console\Command\Upgrade\UpgradeAllCommand::class, 'schedulable' => false, - 'controller' => \Helhum\Typo3Console\Command\UpgradeCommandController::class, - 'controllerCommandName' => 'all', 'runLevel' => \Helhum\Typo3Console\Core\Booting\RunLevel::LEVEL_COMPILE, 'replace' => [ 'install:upgrade:run', @@ -289,18 +287,14 @@ ], 'upgrade:checkextensionconstraints' => [ 'vendor' => 'typo3_console', - 'class' => \Helhum\Typo3Console\Mvc\Cli\Symfony\Command\DummyCommand::class, + 'class' => \Helhum\Typo3Console\Command\Upgrade\UpgradeCheckExtensionConstraintsCommand::class, 'schedulable' => false, - 'controller' => \Helhum\Typo3Console\Command\UpgradeCommandController::class, - 'controllerCommandName' => 'checkExtensionConstraints', 'runLevel' => \Helhum\Typo3Console\Core\Booting\RunLevel::LEVEL_COMPILE, ], 'upgrade:list' => [ 'vendor' => 'typo3_console', - 'class' => \Helhum\Typo3Console\Mvc\Cli\Symfony\Command\DummyCommand::class, + 'class' => \Helhum\Typo3Console\Command\Upgrade\UpgradeListCommand::class, 'schedulable' => false, - 'controller' => \Helhum\Typo3Console\Command\UpgradeCommandController::class, - 'controllerCommandName' => 'list', 'runLevel' => \Helhum\Typo3Console\Core\Booting\RunLevel::LEVEL_COMPILE, 'replace' => [ 'install:upgrade:list', @@ -311,25 +305,19 @@ ], 'upgrade:wizard' => [ 'vendor' => 'typo3_console', - 'class' => \Helhum\Typo3Console\Mvc\Cli\Symfony\Command\DummyCommand::class, + 'class' => \Helhum\Typo3Console\Command\Upgrade\UpgradeWizardCommand::class, 'schedulable' => false, - 'controller' => \Helhum\Typo3Console\Command\UpgradeCommandController::class, - 'controllerCommandName' => 'wizard', 'runLevel' => \Helhum\Typo3Console\Core\Booting\RunLevel::LEVEL_COMPILE, ], 'upgrade:subprocess' => [ 'vendor' => 'typo3_console', - 'class' => \Helhum\Typo3Console\Mvc\Cli\Symfony\Command\DummyCommand::class, + 'class' => \Helhum\Typo3Console\Command\Upgrade\UpgradeSubProcessCommand::class, 'schedulable' => false, - 'controller' => \Helhum\Typo3Console\Command\UpgradeCommandController::class, - 'controllerCommandName' => 'subProcess', ], 'upgrade:checkextensioncompatibility' => [ 'vendor' => 'typo3_console', - 'class' => \Helhum\Typo3Console\Mvc\Cli\Symfony\Command\DummyCommand::class, + 'class' => \Helhum\Typo3Console\Command\Upgrade\UpgradeCheckExtensionCompatibilityCommand::class, 'schedulable' => false, - 'controller' => \Helhum\Typo3Console\Command\UpgradeCommandController::class, - 'controllerCommandName' => 'checkExtensionCompatibility', 'runLevel' => \Helhum\Typo3Console\Core\Booting\RunLevel::LEVEL_COMPILE, ], ]; diff --git a/Documentation/CommandReference/Index.rst b/Documentation/CommandReference/Index.rst index 815ab4fc0..ad831057f 100644 --- a/Documentation/CommandReference/Index.rst +++ b/Documentation/CommandReference/Index.rst @@ -1367,7 +1367,7 @@ Options Options ~~~~~~~ -`--arguments` +`--arguments|-a` Arguments for the wizard prefixed with the identifier, e.g. `compatibility7Extension[install]=0`; multiple arguments separated with comma - Accept value: yes @@ -1395,7 +1395,7 @@ Arguments ~~~~~~~~~ `extensionKeys` - Extension keys to check. Separate multiple extension keys with comma. + Extension keys to check. Separate multiple extension keys with comma @@ -1403,7 +1403,7 @@ Options ~~~~~~~ `--typo3-version` - TYPO3 version to check against. Defaults to current TYPO3 version. + TYPO3 version to check against. Defaults to current TYPO3 version - Accept value: yes - Is value required: yes @@ -1429,7 +1429,7 @@ Options Options ~~~~~~~ -`--all` +`--all|-a` If set, all wizards will be listed, even the once marked as ready or done - Accept value: no @@ -1462,7 +1462,7 @@ Arguments Options ~~~~~~~ -`--arguments` +`--arguments|-a` Arguments for the wizard prefixed with the identifier, e.g. `compatibility7Extension[install]=0` - Accept value: yes @@ -1470,7 +1470,7 @@ Options - Is multiple: no - Default: array () -`--force` +`--force|-f` Force execution, even if the wizard has been marked as done - Accept value: no