Spaces:
No application file
No application file
| declare(strict_types=1); | |
| namespace Mautic\CoreBundle\Helper; | |
| use Composer\Console\Application; | |
| use Mautic\MarketplaceBundle\DTO\ConsoleOutput; | |
| use Psr\Log\LoggerInterface; | |
| use Symfony\Component\Console\Input\ArrayInput; | |
| use Symfony\Component\Console\Output\BufferedOutput; | |
| use Symfony\Component\HttpKernel\KernelInterface; | |
| /** | |
| * Provides several helper functions to interact with Composer (composer require, remove, etc.). | |
| */ | |
| class ComposerHelper | |
| { | |
| public function __construct( | |
| private KernelInterface $kernel, | |
| private LoggerInterface $logger | |
| ) { | |
| } | |
| /** | |
| * Installs a package using its Packagist name. | |
| * | |
| * @param string $packageName The package name, e.g. mautic/example-plugin | |
| * @param bool $dryRun Whether to dry-run the installation. Comes in handy during automated tests | |
| * and to test whether an installation would succeed or not. | |
| */ | |
| public function install(string $packageName, bool $dryRun = false): ConsoleOutput | |
| { | |
| $input = [ | |
| 'command' => 'require', | |
| 'packages' => [$packageName], | |
| ]; | |
| if (true === $dryRun) { | |
| $input['--dry-run'] = null; | |
| } | |
| return $this->runCommand($input); | |
| } | |
| /** | |
| * Removes a package using its Packagist name. | |
| * | |
| * @param string $packageName The package name, e.g. mautic/example-plugin | |
| * @param bool $dryRun Whether to dry-run the removal. Comes in handy during automated tests | |
| * and to test whether an removal would succeed or not. | |
| */ | |
| public function remove(string $packageName, bool $dryRun = false): ConsoleOutput | |
| { | |
| /** | |
| * "composer remove package-name" also triggers an update of all other Mautic dependencies. | |
| * By using the --no-update option first, we can work around that issue and only delete | |
| * this specific package from the composer.json file. | |
| */ | |
| $input = [ | |
| 'command' => 'remove', | |
| 'packages' => [$packageName], | |
| '--no-update' => null, | |
| ]; | |
| if (true === $dryRun) { | |
| $input['--dry-run'] = null; | |
| } | |
| $firstOutput = $this->runCommand($input); | |
| if (0 === $firstOutput->exitCode) { | |
| /** | |
| * Triggering an update of the package we just removed from composer.json | |
| * will remove it from composer.lock and actually delete the plugin folder | |
| * as well. | |
| */ | |
| $input = [ | |
| 'command' => 'update', | |
| 'packages' => [$packageName], | |
| ]; | |
| if (true === $dryRun) { | |
| $input['--dry-run'] = null; | |
| } | |
| $secondOutput = $this->runCommand($input); | |
| // Let's merge the output so that we return all the output we have. | |
| return new ConsoleOutput( | |
| $secondOutput->exitCode, | |
| $firstOutput->output."\n".$secondOutput->output | |
| ); | |
| } | |
| return $firstOutput; | |
| } | |
| /** | |
| * Checks if the given Composer package is installed. | |
| * | |
| * @param string $packageName The package name, e.g. mautic/exmple-plugin | |
| */ | |
| public function isInstalled(string $packageName): bool | |
| { | |
| return \Composer\InstalledVersions::isInstalled($packageName); | |
| } | |
| /** | |
| * Returns a list of installed Composer packages that are of type mautic-plugin. | |
| * | |
| * @return string[] | |
| */ | |
| public function getMauticPluginPackages(): array | |
| { | |
| return \Composer\InstalledVersions::getInstalledPackagesByType('mautic-plugin'); | |
| } | |
| /** | |
| * Updates one or multiple Composer packages. | |
| */ | |
| public function update(?string $packageName = null, bool $dryRun = false): ConsoleOutput | |
| { | |
| $input = [ | |
| 'command' => 'update', | |
| ]; | |
| if (!empty($packageName)) { | |
| $input['packages'] = [$packageName]; | |
| } | |
| if (true === $dryRun) { | |
| $input['--dry-run'] = null; | |
| } | |
| return $this->runCommand($input); | |
| } | |
| /** | |
| * @param array<string,mixed> $input | |
| */ | |
| private function runCommand(array $input): ConsoleOutput | |
| { | |
| $arrayInput = new ArrayInput(array_merge( | |
| $input, [ | |
| '--no-interaction', | |
| '--working-dir' => $this->kernel->getProjectDir(), | |
| ])); | |
| $application = new Application(); | |
| // We don't want our script to stop after running a Composer command | |
| $application->setAutoExit(false); | |
| $this->logger->info('Running Composer command: '.$arrayInput->__toString()); | |
| $output = new BufferedOutput(); | |
| $exitCode = 1; | |
| try { | |
| $exitCode = $application->run($arrayInput, $output); | |
| } catch (\Exception $e) { | |
| $output->writeln('Exception while running Composer command: '.$e->getMessage()); | |
| $this->logger->error('Exception while running Composer command: '.$e->getMessage()); | |
| } | |
| $this->logger->info('Composer command output: '.$output->fetch()); | |
| return new ConsoleOutput($exitCode, $output->fetch()); | |
| } | |
| } | |